from vnnlp import pygp
import random
import math

class GP:
    '''
    Main run the genetic programming
    '''
    def __init__(self, ran, anode):
        self.rand = ran
##        self.nrun = 10
##        self.startseed = 2100        
        #define problem
        #text summarization
        self.problem = pygp.Summarization(self.rand)
##        print 'fitcase'
##        for fitcase in self.problem.fitcase:
##            print '[', fitcase[0], ', ', fitcase[1], ']'
        #genetic
        poplen = 200
        pcross = 0.9
        pmutate = 0.1
        self.genetic = pygp.Genetic(self.problem.term, self.rand, poplen, pcross, pmutate)
        #Initializes satistics
        self.ncross = 0
        self.nmutate = 0
        #Number of generations
        self.generation = 50
        #best individual for each generation
        self.best_current = []
        self.average = []
        self.gen = 0        
        self.anode = anode
        if (len(self.anode) == 0):
            for i in range(self.generation):
                self.anode.append(0)
                
    def ComputeFitness(self):
        summ = 0
        #Compute raw fitness        
        self.genetic.oldpop[0].fitness = self.problem.ComputeRF(self.genetic.oldpop[0])
        mini = self.genetic.oldpop[0].fitness
        nnode = self.genetic.oldpop[0].size
        pos = 0
        for i in range(1, self.genetic.poplen):
            self.genetic.oldpop[i].fitness = self.problem.ComputeRF(self.genetic.oldpop[i])
            nnode += self.genetic.oldpop[i].size
            if(self.genetic.oldpop[i].fitness < mini):
                mini = self.genetic.oldpop[i].fitness
                pos = i
            summ += self.genetic.oldpop[i].fitness
        self.anode[self.gen] += float(nnode)/self.genetic.poplen        
        #copy the best and average
        self.best_current.append(self.genetic.oldpop[pos].Copy(True))
        self.average.append(summ/self.genetic.poplen)
        
        #Compute Adjusted fitness
        self.genetic.AdjustFitness()
        #Finally Compute nomarlized fitness
        self.genetic.NormalizeFitness()

    def Release(self):
        for i in range(self.genetic.poplen):
            del self.genetic
        for i in range(self.generation):
            del self.best_current[i]
        del self.best_current

    def Evolution(self):
        #initialize a population
        self.genetic.RampedInit(6, 0.5)
        self.gen = 0
        while self.gen < self.generation and self.problem.SuccPredicate == False:
            #print 'Compute fitness'
            self.ComputeFitness()
            print 'Generation ', self.gen
##            self.genetic.newpop = []
            l = 0
            while l < self.genetic.poplen:
                #print 'l: ', l
                i = self.genetic.TourSelect(3)
                j = self.genetic.TourSelect(3)
                if (pygp.Flip(self.genetic.pcross, self.rand)):
                    #print 'crossover'
                    crossover = self.genetic.Crossover(self.genetic.oldpop[i],
                                                       self.genetic.oldpop[j])
                    if crossover:#if crossover successful
                        self.genetic.newpop.append(crossover[0])
                        self.genetic.newpop.append(crossover[1])
                    else:
                        self.genetic.newpop.append(self.genetic.oldpop[i])#.Copy(True))
                        self.genetic.newpop.append(self.genetic.oldpop[j])#.Copy(True))
                else:
                    self.genetic.newpop.append(self.genetic.oldpop[i])#.Copy(True))
                    self.genetic.newpop.append(self.genetic.oldpop[j])#.Copy(True))
                if (pygp.Flip(self.genetic.pmutate, self.rand)):
##                    new_individual = self.genetic.Mutation(self.genetic.newpop[l], 5, 'growth')
##                    self.genetic.newpop[l] = new_individual
                    self.nmutate += 1
                if (pygp.Flip(self.genetic.pmutate, self.rand)):
##                    new_individual = self.genetic.Mutation(self.genetic.newpop[l+1], 5, 'growth')
##                    self.genetic.newpop[l+1] = new_individual                    
                    self.nmutate += 1
                l += 2
            self.gen += 1
            self.genetic.oldpop = self.genetic.newpop[:]
            self.genetic.newpop = []

if __name__=='__main__':
    '''
    Run GP
    '''
    startseed = 2001
    nrun = 1
    seed = startseed
    nsuc = 0
    nsuct = 0
    fnsize = open('nsize.txt', 'w')
    fnsuc = open('nsuc.txt', 'w')
    fnbest = open('nbest.txt', 'w')
    fnbestt = open('nbestt.txt', 'w')
    #init var for save data
    anode = []
    
    sumfitness = 0
    while seed < startseed + nrun:
        seed += 1
        print 'run: ', seed
        rand = random.Random()
        rand.seed(seed)
        gp = GP(rand, anode)
        
        gp.Evolution()
        if gp.problem.SuccPredicate:
            nsuc += 1
##            nsuct = nsuct + gsuc
        mini = gp.best_current[0].fitness
        pos = 0
        n = len(gp.best_current);
        for i in range(1, n):
            #print 'gen ', i, 'best fitness: ', gp.best_current[i].fitness
            if mini > gp.best_current[i].fitness:
                mini = gp.best_current[i].fitness
                pos = i
        fnbest.write(str(gp.best_current[pos].fitness) + '\n')
        ftt = gp.problem.ComputeFT(gp.best_current[pos])
        fnbestt.write(str(ftt) + '\n')
        #sumfitness += gp.best_current[pos].fitness
        #print 'best_pos: ', pos
        gp.best_current[pos].Display()
        if seed == startseed + nrun - 1: #ket thuc while
            anode = gp.anode
            for i in range(gp.generation):
                anode[i] = anode[i]/nrun
                fnsize.write(str(anode[i]) + '\n')
    fnsuc.write(str(nsuc))
    fnsize.close()
    fnsuc.close()
    fnbest.close()
    fnbestt.close()
        #print 'nmutate: ', gp.nmutate
    
            
                            
    
        
